<!DOCTYPE html>

<html lang="">

<head>

    <meta charset="UTF-8">

    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">

    <meta name="apple-mobile-web-capable" content="yes">

    <title>录音并传递给后台</title>

</head>

<body>

    <button id="intercomBegin">开始对讲</button>

    <button id="intercomEnd">关闭对讲</button>

</body>

<script type="text/javascript">

    var begin = document.getElementById('intercomBegin');

    var end = document.getElementById('intercomEnd');


    var ws = null; //实现WebSocket

    var record = null; //多媒体对象，用来处理音频


    function init(rec) {

        record = rec;

    }


    //录音对象

    var Recorder = function (stream) {

        var sampleBits = 16; //输出采样数位 8, 16

        var sampleRate = 16000; //输出采样率

        var context = new AudioContext();

        var audioInput = context.createMediaStreamSource(stream);

        var recorder = context.createScriptProcessor(4096, 1, 1);

        var audioData = {

            size: 0, //录音文件长度

            buffer: [], //录音缓存

            bufferALl: [], //录音缓存

            sizeAll: 0, //录音文件长度

            inputSampleRate: 16000, //输入采样率

            inputSampleBits: 16, //输入采样数位 8, 16

            outputSampleRate: sampleRate, //输出采样数位

            oututSampleBits: sampleBits, //输出采样率

            clear: function () {

                this.buffer = [];

                this.size = 0;

            },

            input: function (data) {

                this.buffer.push(new Float32Array(data));

                this.size += data.length;

            },

            compress: function () { //合并压缩

                //合并

                var data = new Float32Array(this.size);

                var offset = 0;

                for (var i = 0; i < this.buffer.length; i++) {

                    data.set(this.buffer[i], offset);

                    offset += this.buffer[i].length;

                }

                //压缩

                var compression = parseInt(this.inputSampleRate / this.outputSampleRate);

                var length = data.length / compression;

                var result = new Float32Array(length);

                var index = 0,

                    j = 0;

                while (index < length) {

                    result[index] = data[j];

                    j += compression;

                    index++;

                }

                return result;

            },

            encodePCM: function () { //这里不对采集到的数据进行其他格式处理，如有需要均交给服务器端处理。

                var sampleRate = Math.min(this.inputSampleRate, this.outputSampleRate);

                var sampleBits = Math.min(this.inputSampleBits, this.oututSampleBits);

                var bytes = this.compress();

                var dataLength = bytes.length * (sampleBits / 8);

                var buffer = new ArrayBuffer(dataLength);

                var data = new DataView(buffer);

                var offset = 0;

                for (var i = 0; i < bytes.length; i++, offset += 2) {

                    var s = Math.max(-1, Math.min(1, bytes[i]));

                    data.setInt16(offset, s < 0 ? s * 0x8000 : s * 0x7FFF, true);

                }

                return new Blob([data]);

            }

        };


        var sendData = function () { //对以获取的数据进行处理(分包)

            var reader = new FileReader();

            reader.onload = e => {

                var outbuffer = e.target.result;

                var arr = new Int8Array(outbuffer);

                if (arr.length > 0) {

                    var tmparr = new Int8Array(1024);
                    console.log(outbuffer);
                    ws.send(outbuffer);

          /*          var j = 0;

                    for (var i = 0; i < arr.byteLength; i++) {

                        tmparr[j++] = arr[i];

                        if (((i + 1) % 1024) == 0) {

                            ws.send(tmparr.buffer);

                            if (arr.byteLength - i - 1 >= 1024) {

                                tmparr = new Int8Array(1024);

                            } else {

                                tmparr = new Int8Array(arr.byteLength - i - 1);

                            }

                            j = 0;

                        }

                        if ((i + 1 == arr.byteLength) && ((i + 1) % 1024) != 0) {

                            ws.send(tmparr.buffer);

                        }

                    }*/

                }

            };

            reader.readAsArrayBuffer(audioData.encodePCM());

            // audioData.clear();//每次发送完成则清理掉旧数据

        };


        this.start = function () {

            audioInput.connect(recorder);

            recorder.connect(context.destination);

        }


        this.stop = function () {

            recorder.disconnect();

        }


        this.getBlob = function () {

            return audioData.encodePCM();

        }


        this.clear = function () {

            audioData.clear();

        }


        recorder.onaudioprocess = function (e) {

            var inputBuffer = e.inputBuffer.getChannelData(0);

            audioData.input(inputBuffer);

            sendData();

        }

    }



    /*
    
    * WebSocket
    
    */

    function useWebSocket() {

        ws = new WebSocket("ws://" + window.location.host + "/websocket/chat/audio");

        ws.binaryType = 'arraybuffer'; //传输的是 ArrayBuffer 类型的数据

        ws.onopen = function () {

            console.log('握手成功');

            console.log(ws.readyState)
            if (ws.readyState === 1) { //ws进入连接状态，则每隔500毫秒发送一包数据

                record.start();

            }

        };


        ws.onmessage = function (msg) {

            console.info(msg)

        }


        ws.onerror = function (err) {

            console.info(err)

        }

    }


    /*
    
    * 开始对讲
    
    */

    begin.onclick = function () {

        navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia;

        if (!navigator.getUserMedia) {

            alert('浏览器不支持音频输入');

        } else {

            navigator.getUserMedia({

                audio: true

            },

                function (mediaStream) {

                    init(new Recorder(mediaStream));

                    console.log('开始对讲');

                    useWebSocket();

                },

                function (error) {

                    console.log(error);

                    switch (error.message || error.name) {

                        case 'PERMISSION_DENIED':

                        case 'PermissionDeniedError':

                            console.info('用户拒绝提供信息。');

                            break;

                        case 'NOT_SUPPORTED_ERROR':

                        case 'NotSupportedError':

                            console.info('浏览器不支持硬件设备。');

                            break;

                        case 'MANDATORY_UNSATISFIED_ERROR':

                        case 'MandatoryUnsatisfiedError':

                            console.info('无法发现指定的硬件设备。');

                            break;

                        default:

                            console.info('无法打开麦克风。异常信息:' + (error.code || error.name));

                            break;

                    }

                }

            )

        }

    }


    /*
    
    * 关闭对讲
    
    */

    end.onclick = function () {

        if (ws) {

            ws.close();

            record.stop();

            console.log('关闭对讲以及WebSocket');

        }

    }

</script>

</html>
